package main

import (
	"fmt"
	"iot-base/common/cache"
	"iot-base/common/ctrltype"

	"iot-base/common/eventtype"
	"iot-base/common/logger"
	"iot-base/common/notify"
	"iot-base/devs/common/loader"
	"sync"
	//"os"

	"strconv"
	"strings"

	"time"

	"github.com/fsnotify/fsnotify"
	"github.com/gogf/gf/v2/container/gset"
	//lua "github.com/yuin/gopher-lua"
)

var g_mapAlarm sync.Map

func watchFile() {
	watcher, err := fsnotify.NewWatcher()

	if err != nil {
		logger.SLog.Error("*********watch error-********", err)
		return
	}
	go func() {
		if watcher != nil {
			defer watcher.Close()
		}
		for {
			select {
			case event, ok := <-watcher.Events:
				if !ok {
					return
				}
				fmt.Println("&&&&&&&&&&&&&&&@@@@@@@@@@@@@", event.Name, event.Op, " ", fsnotify.Write)
				if event.Op == fsnotify.Write {
					reloadLua(event.Name)
				}

			case err, ok := <-watcher.Errors:
				if !ok {
					return
				}
				fmt.Println("error:", err)
			}
		}
	}()
	fmt.Println("*********watch************", getDir())
	watcher.Add(getDir())
}

func main() {

	//done := make(chan bool)
	//ctrl.SubCtrlCmd()
	watchFile()
	logger.SLog.Warn("*********--------lscript-----begins---********")
	loader.SetParamEx(false, "lscript", 10, eachDev)
	loader.SetThingChangedCallback(func(ctype string, id string) {
		g_mapAlarm.Delete(id)
	})
	loader.SubCtrlHandler(func(pCmd *ctrltype.CtrlCmd) (map[string]interface{}, error) {

		tid := pCmd.ThingID
		pThing, terr := cache.GetThing(tid)
		if pThing != nil {
			pLib, err := loadLibByDev(pThing)
			if err != nil {
				return nil, err
			}
			params := make(map[string]string)
			for k, v := range pThing.Params {
				params[k] = v
			}
			for ck, cv := range pCmd.Params {
				if cv != nil {
					str := fmt.Sprintf("%v", cv)
					params[ck] = str
				}
			}
			params["service_id"] = pCmd.ID
			return runLuaFunction(tid, "ctrl", params, pLib)
		}
		return nil, terr

	})
	wg := sync.WaitGroup{}
	wg.Add(1)
	wg.Wait()
	//<-done

}

func handleData(id string, errf error, mapData map[string]interface{}) (isoffline bool) {

	if errf == nil && mapData != nil {
		isoffline = false
		now := time.Now().Unix()

		for sk, v := range mapData {
			ps := strings.Split(sk, SPLIT)
			nLen := len(ps)
			sid := ""
			pid := ""
			index := 0
			if nLen > 0 && nLen <= 3 {
				pid = ps[0]
				if nLen >= 2 {
					sid = ps[1]
				}
				if nLen == 3 {
					sindex, err := strconv.ParseInt(ps[2], 10, 32)
					if err != nil {
						logger.SLog.Error(id, " lua  getData ret error ", " sk:", sk, err)
						continue
					} else {
						index = int(sindex)
					}
				}
			}
			notify.RawData(id, pid, sid, index, v, now, now)
		}

	} else if errf != nil {
		isoffline = true
	} else {
		isoffline = false
	}
	return isoffline
}

func reportOfflineAlarm(id string) {
	var curAlarm eventtype.Alarm
	curAlarm.TID = id
	curAlarm.AlarmID = "offline"
	curAlarm.Flag = "BEGIN"
	curAlarm.Checker = "lua script"
	notify.RawAlarm(&curAlarm)
}

func createAlarm(tid, aid, flag string) *eventtype.Alarm {
	var curAlarm eventtype.Alarm

	initAlarm(tid, aid, flag, &curAlarm)
	return &curAlarm
}

func initAlarm(id, aid, flag string, curAlarm *eventtype.Alarm) {

	curAlarm.TID = id
	curAlarm.Flag = flag
	ps := strings.Split(aid, SPLIT)
	nLen := len(ps)
	if nLen >= 1 {
		curAlarm.AlarmID = ps[0]
		if nLen >= 2 {
			curAlarm.Mindex, _ = strconv.ParseInt(ps[1], 10, 64)
		}
	}
}

func syncAlarms(id string, alarmSet *gset.Set) {
	size := alarmSet.Size()
	if size == 0 {
		notify.ReportAllAlarms(nil, []string{id})
		return
	}
	fmt.Println("syncalarms --------------", size)
	alarms := make([]*eventtype.Alarm, size, size)
	var i = 0
	alarmSet.Iterator(func(v interface{}) bool {

		if v != nil {
			alarms[i] = createAlarm(id, v.(string), "BEGIN")
		}
		i++
		return true
	})
	fmt.Println("alarms----------", alarms[0])
	notify.ReportAllAlarms(alarms, []string{id})
}

func reportAlarm(id, flag string, alarmSet *gset.Set) {
	var curAlarm eventtype.Alarm
	var i = 0
	alarmSet.Iterator(func(v interface{}) bool {
		i++
		if v != nil {
			initAlarm(id, v.(string), flag, &curAlarm)
			notify.RawAlarm(&curAlarm)
		}
		return true
	})
}
